package com.simple.base.dao;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;

import com.simple.util.exception.SimpleSystemException;
import com.simple.util.object.PageInfoBean;

public abstract class AbstractBaseDAO{

	@Autowired    
    private PropertiesFactoryBean hibernateProperties;
	
	
	protected abstract SessionFactory getSessionFactory();
	
	/**
	 * 根据id获得对象
	 * @param <X>
	 * @param clazz
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <X> X get(final Class<X> clazz, final Serializable id) {
		return (X) this.getSession().get(clazz, id);
	}

	/**
	 * 删除对象
	 * @param entity
	 */
	protected void delete(final Object entity) {
		this.getSession().delete(entity);
	}

	/**
	 * 根据ID删除对象,load提高性能
	 * @param <X>
	 * @param clazz
	 * @param id
	 */
	protected <X> void delete(final Class<X> clazz, final Serializable id) {
		delete(this.getSession().load(clazz, id));
	}
	
	
	@SuppressWarnings("unchecked")
	protected <X> X save(final Object entity) {
		return (X) this.get(entity.getClass(), this.getSession().save(entity));
	}
	
	protected void update(final Object entity) {
		this.getSession().update(entity);
	}
	
	protected void saveOrUpdate(final Object entity) {
		this.getSession().saveOrUpdate(entity);
	}
	
	protected <X> void saveOrUpdate(final List<X> entities) {
		final int cacheSize = getBatchSize();
		Session session = this.getSession();
		for (int i = 0; i < entities.size(); i++) {
			X entity = entities.get(i);
			session.saveOrUpdate(entity);
			if (i % cacheSize == 0) {
				session.flush();
				session.clear();
			}
		}
	}
	
	/**
	 * hql更新
	 * @param hql
	 * @return
	 */
	protected int executeUpdate(final String hql) {
		return this.createQuery(hql).executeUpdate();
	}
	
	/**
	 * 有条件参数的hql更新
	 * @param hql
	 * @param params
	 * @return
	 */
	protected int executeUpdate(final String hql, List<?extends Object> params) {
		return this.createQuery(hql, params).executeUpdate();
	}
	
	
	/**
	 * 有条件参数的hql更新
	 * @param hql
	 * @param params
	 * @param splitParams参数是否拆分，传入null或ture表示拆分参数，false参数不拆分，适合只有一个参数的情况
	 * @return
	 */
	protected int executeUpdate(final String hql, List<?extends Object> params,Boolean splitParams) {
		return this.createQuery(hql, params,splitParams).executeUpdate();
	}
	
	/**
	 * 批量删除实体，不推荐
	 * @param <X>
	 * @param entities
	 */
	protected <X> void deletes(final List<X> entities) {
		final int cacheSize = getBatchSize();
		Session session = this.getSession();
		for (int i = 0; i < entities.size(); i++) {
			X entity = entities.get(i);
			session.delete(entity);
			if (i % cacheSize == 0) {
				session.flush();
				session.clear();
			}
		}
	}

	/**
	 * 保存的实体对象
	 * @param entity
	 */
	/*
	protected void merge(final Object entity) {
		getSession().merge(entity);
	}
	*/
	
	/**
	 * 批量保存实体
	 * @param <X>
	 * @param entities
	 */
	/*
	protected <X> void merges(final List<X> entities) {
		final int cacheSize = getBatchSize();
		Session session = this.getSession();
		for (int i = 0; i < entities.size(); i++) {
			X entity = entities.get(i);
			session.merge(entity);
			if (i % cacheSize == 0) {
				session.flush();
				session.clear();
			}
		}
	}
	*/
	
	
	/**
	 * 没有条件参数的HQL查询单个对象
	 * @param hql
	 * @return
	 */
	protected Object get(final String hql){
		return this.createQuery(hql).uniqueResult();
	}
	
	/**
	 * 单一条件参数的HQL查询单个对象
	 * @param hql
	 * @param param
	 * @return
	 */
	protected Object get(final String hql,final Object param){
		return this.createQuery(hql).setParameter(0, param).uniqueResult();
	}
	
	/**
	 * 支持条件参数的HQL查询单个对象
	 * @param hql
	 * @param params
	 * @return
	 */
	protected Object get(final String hql,final List<?extends Object> params){
		return this.createQuery(hql, params).uniqueResult();
	}
	
	/**
	 * 没有条件参数的HQL查询
	 * @param <X>
	 * @param hql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <X> List<X> query(final String hql){
		return this.createQuery(hql).list();
	}
	
	/**
	 * 单一条件参数的HQL查询
	 * @param <X>
	 * @param hql
	 * @param param
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <X> List<X> query(final String hql,final Object param){
		return this.createQuery(hql).setParameter(0, param).list();
	}
	
	/**
	 * 支持条件参数的HQL查询
	 * @param <X>
	 * @param listHql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <X> List<X> query(final String hql,final List<?extends Object> params){
		return this.createQuery(hql, params).list();
	}
	
	/**
	 * 没有条件和排序参数的对象化查询
	 * @param <X>
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <X> List<X> query(final Class<X> clazz){
		return this.createCriteria(clazz).list();
	}
	
	/**
	 * 单一条件的对象化查询
	 * @param <X>
	 * @param clazz
	 * @param criterion
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <X> List<X> query(final Class<X> clazz,final Criterion criterion){
		return this.createCriteria(clazz).add(criterion).list();
	}
	
	/**
	 * 支持条件没有排序的对象化查询
	 * @param <X>
	 * @param clazz
	 * @param criterions
	 * @return
	 */
	protected <X> List<X> query(final Class<X> clazz,final List<Criterion> criterions){
		return this.query(clazz, criterions, null);
	}
	
	/**
	 * 单一排序的对象化查询
	 * @param <X>
	 * @param clazz
	 * @param criterions
	 * @return
	 */
	protected <X> List<X> query(final Class<X> clazz,final Order order){
		final List<Order> orderList = new ArrayList<Order>();
		orderList.add(order);
		return this.query(clazz, null, orderList);
	}
	
	/**
	 * 支持条件和排序参数的对象化查询
	 * @param <X>
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <X> List<X> query(final Class<X> clazz,final List<Criterion> criterions, final List<Order> orders) {
		return this.createCriteria(clazz, criterions, orders).list();
	}

	
	private Query createQuery(final String hql){
		return this.getSession().createQuery(hql);
	}
	
	private Query createQuery(final String hql,final List<?extends Object> params){
		return this.createQuery(hql, params, null);
	}
	
	private Query createQuery(final String hql,final List<?extends Object> params,Boolean splitParams){
		Query query=this.createQuery(hql);
		if(splitParams==null||splitParams==true){
			if (params != null && !params.isEmpty()) {
				int size = params.size();
				for (int i = 0; i < size; i++) {
					query.setParameter(i, params.get(i));
				}
			}
		}else{
			if (params != null && !params.isEmpty()) {
				query.setParameter(0, params);	
			}
		}
		return query;
		
	}
	
	@SuppressWarnings({ "unused", "rawtypes" })
	private Query createQuery(final String hql,final Map<String,?extends Object> namedParames){
		Query query=this.createQuery(hql);
		if(namedParames!=null&&!namedParames.isEmpty()){
			Iterator iter = namedParames.entrySet().iterator();
			while (iter.hasNext()) {
				Map.Entry entry = (Map.Entry) iter.next();
				query.setParameter((String)entry.getKey(), entry.getValue());
			}
		}
		return query;
	}
	
	private SQLQuery createSQLQuery(final String sql){
		return this.getSession().createSQLQuery(sql);
	}
	
	@SuppressWarnings("unused")
	private SQLQuery createSQLQuery(final String sql,final List<?extends Object> params,Boolean splitParams){
		SQLQuery sqlQuery=this.createSQLQuery(sql);
		if(splitParams==null||splitParams==false){
			if (params != null && !params.isEmpty()) {
				int size = params.size();
				for (int i = 0; i < size; i++) {
					sqlQuery.setParameter(i, params.get(i));
				}
			}
		}else{
			if (params != null && !params.isEmpty()) {
				sqlQuery.setParameter(0, params);
			}
		}
		return sqlQuery;
	}
	
	/**
	 * 获取Criteria
	 * @param <X>
	 * @param clazz
	 * @return
	 */
	protected <X> Criteria createCriteria(final Class<X> clazz){
		 return this.getSession().createCriteria(clazz);
	}
	
	/**
	 * 获取Criteria
	 * @param <X>
	 * @param clazz
	 * @param criterions
	 * @param orders
	 * @return
	 */
	protected <X> Criteria createCriteria(final Class<X> clazz,
			final List<Criterion> criterions, final List<Order> orders) {
		Criteria criteria =this.createCriteria(clazz);
		// 添加查询条件
		if(criterions!=null&&!criterions.isEmpty()){
			for (Criterion c : criterions) {
				criteria.add(c);
			}
		}
		// 添加排序条件
		if(orders!=null&&!orders.isEmpty()){
			for (Order order : orders) {
				criteria.addOrder(order);
			}
		}
		return criteria;
	}

	

	protected int getBatchSize(){
        int size = 0;
        try {
            final Properties pf =  hibernateProperties.getObject();
            size = Integer.valueOf(String.valueOf(pf.get("hibernate.jdbc.batch_size")));
        } catch (IOException e) {
            throw new SimpleSystemException("message.system.error",e);
        } 
        return size;
    }
	
	protected Session getSession(){
		return getSessionFactory().getCurrentSession();
	}
	
	@SuppressWarnings("rawtypes")
    protected int getTotalCount(final String hql, final Map paramMap) {
    	final Query query = this.getSession().createQuery(hql);
    	if(paramMap != null){
    		final Iterator it = paramMap.keySet().iterator();
            while (it.hasNext()) {
            	final Object key = it.next();
                
                if(paramMap.get(key)  instanceof   java.util.List<?>){
                    query.setParameterList(key.toString(), (List)paramMap.get(key));
                } else{
                    query.setParameter(key.toString(), paramMap.get(key));
                }
            }

    	}
        return ((Long) query.list().get(0)).intValue();

    }

	@SuppressWarnings("rawtypes") 
    protected List <?> queryListByPage(final String primaryKey,final String hql, final Map paramMap,final PageInfoBean pageInfoBean){
        final String strhql = " " + hql + " order ";
        final String hqlTemp = strhql.toLowerCase(Locale.getDefault());
        final StringBuffer hqlCount = new StringBuffer("select count("+primaryKey+")");
        
        if(hqlTemp.indexOf(" group ")>0){
            hqlCount.append(strhql.subSequence(hqlTemp.indexOf(" from "), hqlTemp.indexOf(" group ")));
        }else{
            hqlCount.append(strhql.subSequence(hqlTemp.indexOf(" from "), hqlTemp.indexOf(" order ")));
        }
        final int size = getTotalCount(hqlCount.toString(), paramMap);
        pageInfoBean.setTotalRecordCount(size);
        pageInfoBean.doReviseData();
        final Query query = getSession().createQuery(hql);
        if(paramMap != null){
        	final Iterator <?> it = paramMap.keySet().iterator();
            while (it.hasNext()) {
            	final Object key = it.next();
                if(paramMap.get(key)  instanceof   java.util.List<?>){
                    query.setParameterList(key.toString(), (List)paramMap.get(key));
                } else{
                    query.setParameter(key.toString(), paramMap.get(key));
                }
            }
        }
        query.setFirstResult(pageInfoBean.getRecordCountInOnePage()*(pageInfoBean.getCurPageNo() - 1));
        query.setMaxResults(pageInfoBean.getRecordCountInOnePage());
        return query.list();
    }
}
